package com.tool.o2m.model;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Table {
    private static final Integer MAX_ROW_SIZE = 65535;

    public String tableName;

    public String comments;

    public List<TableColumn> columns;

    public List<TableKey> keys;

    /** varchar类型行大小*/
    public Integer varcharRowSize;

    /** 需要变为text类型的列 */
    public List<String> toTextColumns;

    /**
     * 转成MySQL脚本
     *
     * @return
     */
    public String toMySQLScript(){
        StringBuilder sb = new StringBuilder();
        sb.append("DROP TABLE IF EXISTS `" + this.tableName.toLowerCase() + "`;\n");
        sb.append("CREATE TABLE `" + this.tableName.toLowerCase() + "` ( \n");
        for(TableColumn tableColumn: this.columns){
            sb.append("  " + tableColumn.toMysqlScript(this.toTextColumns) + ",\n");
        }

        // 处理主键和索引
        if(CollUtil.isNotEmpty(this.keys)){
            for (TableKey tableKey : this.keys) {
                sb.append("  " + tableKey.toMysqlScript() + ",\n");
            }
        }

        sb.deleteCharAt(sb.lastIndexOf(","));

        // 指定表的数据库引擎为InnoDB
        sb.append("\n) ENGINE=InnoDB ");
        // 指定表的默认字符集和排序规则
        sb.append("DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_0900_ai_ci");

        if(StrUtil.isNotEmpty(this.comments)){
            sb.append(" COMMENT='" + this.comments + "'");
        }
        sb.append(";\n\n\n");
        return sb.toString();
    }

    public void setKeys(List<TableKey> keys) {
        if (CollUtil.isEmpty(keys)) {
            this.keys = new ArrayList<>();
            return;
        }
        // 转换列表达式
        for (TableKey key : keys) {
            key.convertColumnExpression(key.getColumnExpression());
        }
        this.keys = this.mergeColumnNameGroupByKeyName(keys);
    }

    // 按键名分组合并列名
    private List<TableKey> mergeColumnNameGroupByKeyName(List<TableKey> keys) {
        List<TableKey> resultList = new ArrayList<>();
        if(CollUtil.isEmpty(keys)){
            return resultList;
        }

        // 按表名+键名+ 键类型分组
        Map<String, List<TableKey>> tableKeyMap = keys.stream().collect(Collectors.groupingBy(o -> o.getTableName()
                + StrUtil.DASHED + o.getKeyName()
                + StrUtil.DASHED + o.getKeyType()));

        for (String key : tableKeyMap.keySet()) {
            List<TableKey> groupKeyList = tableKeyMap.get(key);
            TableKey groupKey = groupKeyList.get(0);
            TableKey resultKey = new TableKey();
            resultKey.setTableName(groupKey.getTableName());
            resultKey.setKeyName(groupKey.getKeyName());
            resultKey.setKeyType(groupKey.getKeyType());
            // 获取列名
            String columnName = groupKeyList.stream().sorted(Comparator.comparing(TableKey::getColumnPosition))
                    .map(o -> "`" + o.getColumnName() + "`").collect(Collectors.joining(","));
            resultKey.setColumnName(columnName);

            // 主键
            if(StrUtil.equalsIgnoreCase(resultKey.getKeyType(), "PRIMARY")){
                resultKey.setKeyTypeSort(1);
            }
            // 唯一索引
            else if(StrUtil.equalsIgnoreCase(resultKey.getKeyType(), "UNIQUE")){
                resultKey.setKeyTypeSort(2);
            }
            // 普通索引
            else {
                resultKey.setKeyTypeSort(3);
            }
            resultList.add(resultKey);
        }

        return resultList.stream().sorted(Comparator.comparingInt(TableKey::getKeyTypeSort).
                thenComparing(TableKey::getKeyName)).collect(Collectors.toList());
    }

    public void setToTextColumns(List<TableColumn> tableColumnList) {
        this.toTextColumns = new ArrayList<>();
        if (this.varcharRowSize < MAX_ROW_SIZE) {
            return;
        }

        // 过滤出varchar类型的字段，并按长度倒序排序
        List<TableColumn> varcharColumnList = tableColumnList.stream().filter(c -> "VARCHAR2".equals(c.getDataType()) || "NVARCHAR2".equals(c.getDataType()))
                .sorted(Comparator.comparing(TableColumn::getCharLength, Comparator.reverseOrder()).thenComparing(TableColumn::getColumnId, Comparator.reverseOrder()))
                .collect(Collectors.toList());

        Integer rowSize = this.varcharRowSize;
        for (TableColumn column : varcharColumnList) {
            this.toTextColumns.add(column.getColumnName());
            rowSize = rowSize - (column.getCharLength() * 4);
            if (rowSize < MAX_ROW_SIZE) {
                return;
            }
        }
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public String getComments() {
        return comments;
    }

    public void setComments(String comments) {
        this.comments = comments;
    }

    public List<TableColumn> getColumns() {
        return columns;
    }

    public void setColumns(List<TableColumn> columns) {
        this.columns = columns;
    }

    public List<TableKey> getKeys() {
        return keys;
    }
}
